package org.wisdom.security.utils;

import io.jsonwebtoken.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.wisdom.security.dto.ValidatedToken;
import org.wisdom.security.exception.TokenNotValidException;

import java.security.Key;
import java.text.MessageFormat;

/**
 * token 验证器
 * 
 * @author zhangzhiyan
 * @date 2021/08/20 11:24
 */
@Slf4j
@AllArgsConstructor
public class TokenValidator {

    private final Key key;

    public ValidatedToken validate(String token) throws TokenNotValidException {
        try {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key).parseClaimsJws(token);
            return ValidatedToken.builder().token(token).subject(String.valueOf(claimsJws.getBody().get("username"))).userId(String.valueOf(claimsJws.getBody().get("userId"))).build();
        } catch (UnsupportedJwtException e) {
            throw new TokenNotValidException(MessageFormat.format(
                "Provided JSON Web Token = {0} does not represent supported Claims JWT, error message = {1}.",
                getTokenForLog(token), e.getMessage()), e);
        } catch (MalformedJwtException e) {
            throw new TokenNotValidException(MessageFormat.format(
                "Provided JSON Web Token = {0} is invalid or has invalid format, error message = {1}.",
                getTokenForLog(token), e.getMessage()), e);
        } catch (ExpiredJwtException e) {
            throw new TokenNotValidException(
                MessageFormat.format("Provided JSON Web Token = {0} is expired, error message = {1}.",
                    getTokenForLog(token), e.getMessage()),
                e);
        } catch (IllegalArgumentException e) {
            throw new TokenNotValidException(
                MessageFormat.format("Provided JSON Web Token = {0} is null, whitespace or empty, error message = {1}.",
                    getTokenForLog(token), e.getMessage()),
                e);
        } catch (Exception e) {
            throw new TokenNotValidException(MessageFormat.format(
                "Unable to authenticate user with provided JSON Web Token = {0}, unknown exception occur, error message = {1}.",
                getTokenForLog(token), e.getMessage()), e);
        }
    }

    private String getTokenForLog(String token) {
        if (StringUtils.isBlank(token)) {
            return token;
        }
        return DigestUtils.sha256Hex(token);
    }
}